#include "wxemail.h"
#include "wxbase64.h"


#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxArrayMimePart);

struct wxMimeTypeMapping
{
	const wxChar* extension;
	const wxChar* mainType;
	const wxChar* subType;
};

// extension, main type, sub type
// TODO: must be merged / integrated / substituted with wxFileType
static const wxMimeTypeMapping g_mimeTypeMappings[] =
{
	{ _T("txt"), _T("text"), _T("plain") },
	{ _T("htm"), _T("text"), _T("html") },
	{ _T("html"), _T("text"), _T("html") },
	{ _T("gif"), _T("image"), _T("gif") },
	{ _T("png"), _T("image"), _T("png") },
	{ _T("jpg"), _T("image"), _T("jpeg") },
	{ _T("jpeg"), _T("image"), _T("jpeg") },
	{ _T("pdf"), _T("application"), _T("pdf") },
	{ _T("wav"), _T("audio"), _T("wav") },
	{ _T("mp3"), _T("audio"), _T("mpeg") },
	{ _T("doc"), _T("application"), _T("msword") }
};

wxMimePart::wxMimePart(const wxFileName& fileName,
                       bool is_inline,const wxString& mainType,
                       const wxString& subType) :
    m_fileName(fileName),
    m_inline(is_inline),
    m_mainType(mainType),
    m_subType(subType)
{
    if(m_mainType.IsNull() || m_subType.IsNull()) {
	// setup default encoding
	m_mainType = _T("application");
	m_subType = _T("octet-stream");
        
	// try to determine encoding by filename extension
	wxString ext = fileName.GetExt().Lower();
	for (unsigned int i = 0; 
             i < sizeof(g_mimeTypeMappings) / sizeof(wxMimeTypeMapping); i++) {
            if (g_mimeTypeMappings[i].extension == ext) {
                m_mainType = g_mimeTypeMappings[i].mainType;
                m_subType = g_mimeTypeMappings[i].subType;
                break;
            }
	}
    } 
}

wxMimePart::wxMimePart(const wxString& data,
                       bool is_inline,const wxString& mainType,
                       const wxString& subType,const wxString& fileName) 
{    
    m_data = data;
    m_inline = is_inline;
    m_mainType = mainType;
    m_subType = subType;
    m_fileName = fileName;

    // Nothing to do?    
}


void wxMimePart::Encode(wxOutputStream& out)
{
    if(m_data.IsNull()) {   
        // TODO: error handling for every return
        // TODO: encoding it on-the-fly without loading it all in memory
        wxFileInputStream in(m_fileName.GetFullPath());
        if (!in.Ok()) return;
    
        // determine file length
        // TODO: perhaps this can be added to wxFileName for size()
        in.SeekI(0, wxFromEnd);
        size_t len = (size_t) in.TellI();
        in.SeekI(0);
        // that's possible for windows (#include <sys/types.h> 
        // and #include <sys/stat.h>):
        // struct _stat lenStat;
        // if (_stat(filename, &lenStat) == -1) return error;
        // size_t len = (size_t) lenStat.st_size;
    
        if (len == 0) return;
    
        // read file
        wxUint8* pData = new wxUint8[len];
        if (!pData) {
            wxASSERT_MSG(pData != NULL, wxT("out of memory"));
            return;
        }
        in.Read(pData, len);
    
        // write encoded mime part to stream
        wxString cr(wxT("\x00d\x00a"));
        wxString result;
        result << wxT("Content-Type: ") << m_mainType << wxT("/") << m_subType;
        if(! m_inline) {
            result << wxT("; name=\"") << m_fileName.GetFullName() + wxT("\"") << cr 
                   << wxT("Content-Disposition: attachment; filename=\"") 
                   << m_fileName.GetFullName() << wxT("\"");
        }
        result << cr << wxT("Content-Transfer-Encoding: base64") << cr << cr
               << wxBase64::Encode(pData, len) << cr;
        //cout << ">>" << result << "<<" << endl;
        out.Write((const char*) result.ToAscii(), result.Length());
    } else {
        // We had data as string
        
        size_t len = m_data.Len();
        const wxUint8* pData = (wxUint8*)(const char*) m_data.ToAscii();

        // write encoded mime part to stream
        wxString cr(wxT("\x00d\x00a"));
        wxString result;
        result << wxT("Content-Type: ") << m_mainType << wxT("/") << m_subType;
        if(! m_inline) {
            result << wxT("; name=\"") << m_fileName.GetFullName() + wxT("\"") << cr 
                   << wxT("Content-Disposition: attachment; filename=\"") 
                   << m_fileName.GetFullName() << wxT("\"");
        }
        result << cr << wxT("Content-Transfer-Encoding: base64") << cr << cr
               << wxBase64::Encode(pData, len) << cr;
        //cout << ">>" << result << "<<" << endl;
        out.Write((const char*) result.ToAscii(), result.Length());        
    }
}

